package cn.wizzer.app.user.util;

import cn.hutool.crypto.SecureUtil;
import cn.wizzer.app.sys.modules.models.constant.CurrencyConstant;
import cn.wizzer.app.user.modules.models.UserWithdraw;
import cn.wizzer.app.user.modules.models.constant.GlobalPayParamConstant;
import cn.wizzer.app.user.modules.models.dto.GlobalPayRechargeDTO;
import cn.wizzer.app.user.modules.models.dto.GlobalPayWithdrawDTO;
import cn.wizzer.app.user.modules.models.enums.PayChannel;
import cn.wizzer.framework.util.HttpUtil;
import cn.wizzer.framework.util.Id;
import cn.wizzer.framework.util.JSONUtil;
import cn.wizzer.framework.util.Result;
import com.alibaba.fastjson.JSONObject;
import org.nutz.lang.Strings;
import org.nutz.log.Log;
import org.nutz.log.Logs;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * 印尼GlobalPay
 */
public class GlobalPayUtil {
    private static final Log log = Logs.get();

    public static String send(String url, Map<String, Object> params) throws IOException {
        String body = HttpUtil.createRequest()
                .setUrl(url)
                .setHeader("Content-Type", "application/x-www-form-urlencoded")
                .setParam(params)
                .send(HttpUtil.HTTP_METHOD.POST_JSON)
                .getBodyAndClose();
        log.info("GlobalPayUtil.send(url:" + url + ",params:" + JSONUtil.toJSONString(params) + ")->result:" + body);
        return body;
    }


    /**
     * 充值
     *
     * @param amount       支付金额
     * @param notifyUrl    回调地址
     * @param outtradeno   订单号
     * @param currencyName 币种简写(大写)
     * @param channel      支付通道
     * @return
     * @throws UnsupportedEncodingException
     */
    public static Map<String, Object> createPayParam(String amount, String notifyUrl, String outtradeno, String currencyName, PayChannel channel) throws UnsupportedEncodingException {
        Map<String, Object> params = new HashMap<>();
        //金额
        params.put("order_amount", amount);
        String secret = GlobalPayParamConstant.IDR_SECRET;
        // 根据国家配置参数
        if (CurrencyConstant.IDR.equals(currencyName)) {
            //商户ID
            params.put("mer_no", GlobalPayParamConstant.IDR_MER_NO);
            //第三方账户名(固定写死)
            params.put("pname", GlobalPayParamConstant.IDR_PNAME);
            //邮箱(固定写死)
            params.put("pemail", GlobalPayParamConstant.IDR_PEMAIL);
            //手机号(固定写死)
            params.put("phone", GlobalPayParamConstant.IDR_PHONE);
            //银行编码(固定写死)
            params.put("bankCode", GlobalPayParamConstant.IDR_BANKCODE);
            //国家简写(大写）
            params.put("countryCode", GlobalPayParamConstant.IDR_COUNTRYCODE);
            //根据支付通道选择支付编码
            if (PayChannel.GLOBALPAY.equals(channel)) {
                params.put("busi_code", GlobalPayParamConstant.IDR_EBANK_CODE);
            } else if (PayChannel.GLOBALPAY_OVO.equals(channel)) {
                params.put("busi_code", GlobalPayParamConstant.IDR_OVO_CODE);
            }
        } else if (CurrencyConstant.THB.equals(currencyName)) {
            secret = GlobalPayParamConstant.THB_SECRET;
            params.put("mer_no", GlobalPayParamConstant.THB_MER_NO);
            params.put("pname", GlobalPayParamConstant.THB_PNAME);
            //邮箱(固定写死)
            params.put("pemail", GlobalPayParamConstant.THB_PEMAIL);
            //手机号(固定写死)
            params.put("phone", GlobalPayParamConstant.THB_PHONE);
            //银行编码(固定写死)
            params.put("bankCode", GlobalPayParamConstant.THB_BANKCODE);
            //国家简写(大写）
            params.put("countryCode", GlobalPayParamConstant.THB_COUNTRYCODE);
            //根据支付通道选择支付编码
            if (PayChannel.GLOBALPAY.equals(channel)){
                params.put("busi_code", GlobalPayParamConstant.THB_EBANK_CODE);
                // 泰国网银业务必须上送银行账号
                params.put("accNo", GlobalPayParamConstant.THB_ACCNO);
            } else if (PayChannel.GLOBALPAY_QRCODE.equals(channel)) {
                params.put("busi_code", GlobalPayParamConstant.THB_QRCODE_CODE);
            } else if (PayChannel.GLOBALPAY_TRUEMONEY.equals(channel)) {
                params.put("busi_code", GlobalPayParamConstant.THB_TRUEMONEY_CODE);
            }
        } else if (CurrencyConstant.INR.equals(currencyName)) {
            secret = GlobalPayParamConstant.INR_SECRET;
            params.put("mer_no", GlobalPayParamConstant.INR_MER_NO);
            params.put("pname", GlobalPayParamConstant.INR_PNAME);
            //邮箱(固定写死)
            params.put("pemail", GlobalPayParamConstant.INR_PEMAIL);
            //手机号(固定写死)
            params.put("phone", GlobalPayParamConstant.INR_PHONE);
            //国家简写(大写）
            params.put("countryCode", GlobalPayParamConstant.INR_COUNTRYCODE);
            //UPI支付编码
            params.put("busi_code", GlobalPayParamConstant.INR_UPI_CODE);
            //银行编码(固定写死) 印度暂不支持网银支付
//            params.put("bankCode", GlobalPayParamConstant.INR_BANKCODE);
        }
        //商户订单号
        params.put("mer_order_no", outtradeno);
        //币种简写(大写)
        params.put("ccy_no", currencyName);
        // 商品名称
        params.put("goods", "254100");
        //成功回调地址
        params.put("notifyUrl", notifyUrl);
        String[] keys = params.keySet().toArray(new String[]{});

        StringBuilder stringBuilder = new StringBuilder();
        Arrays.sort(keys);
        for (String key : keys) {
            String val = String.valueOf(params.get(key));
            if (Strings.isBlank(val)) {
                continue;
            }
            stringBuilder.append("&").append(key).append("=").append(val);
        }
        //排序后的参数
        String encodeParams = stringBuilder.deleteCharAt(0).toString();
        //拼接商户secret
        String strToHash = encodeParams + "&key=" + secret;
        //sign
        String hashResult = SecureUtil.md5(strToHash);
        //数字签名
        params.put("sign", hashResult);
        return params;
    }

    /**
     * 校验充值回调
     *
     * @param globalPay
     * @param secret
     * @return
     * @throws UnsupportedEncodingException
     */
    public static boolean verifyRechargeNotify(GlobalPayRechargeDTO globalPay, String secret) throws UnsupportedEncodingException {
        Map<String, String> params = Result.createMap("busi_code", globalPay.getBusi_code(),
                "err_code", globalPay.getErr_code(),
                "err_msg", globalPay.getErr_msg(),
                "mer_no", globalPay.getMer_no(),
                "mer_order_no", globalPay.getMer_order_no(),
                "order_amount", globalPay.getOrder_amount(),
                "order_no", globalPay.getOrder_no(),
                "order_time", globalPay.getOrder_time(),
                "pay_amount", globalPay.getPay_amount(),
                "pay_time", globalPay.getPay_time(),
                "reserver", globalPay.getReserver(),
                "status", globalPay.getStatus());
        String[] keys = params.keySet().toArray(new String[]{});
        Arrays.sort(keys);

        StringBuilder sb = new StringBuilder();
        Arrays.sort(keys);
        for (String key : keys) {
            String val = params.get(key);
            if (Strings.isBlank(val)) {
                continue;
            }
            sb.append("&").append(key).append("=").append(val == null ? "" : val);
        }
        //拼接商户secret
        String strToHash = sb.deleteCharAt(0).toString() + "&key=" + secret;
        //sign
        String hashResult = SecureUtil.md5(strToHash);
        return hashResult.equals(globalPay.getSign());
    }

    /**
     * 代付
     *
     * @param mer_order_no 商户订单号
     * @param acc_no       收款账号
     * @param acc_name     收款户名
     * @param ccy_no       币种
     * @param order_amount 金额
     * @param bank_code    银行编码
     * @param mobile_no    手机号 否
     * @param province     省份 否 印度银行卡代付必填(IFSC)
     * @param notifyUrl    回调地址
     * @param summary      备注
     * @return
     * @throws UnsupportedEncodingException
     */
    public static Map<String, Object> createWithdrawParam(String mer_order_no, String acc_no, String acc_name, String ccy_no, String order_amount,
                                                          String bank_code, String mobile_no, String province, String notifyUrl,
                                                          String summary) throws UnsupportedEncodingException {
        String secret = GlobalPayParamConstant.IDR_SECRET;
        Map<String, Object> params = new HashMap<>();
        if (CurrencyConstant.IDR.equals(ccy_no)) {
            params.put("mer_no", GlobalPayParamConstant.IDR_MER_NO);
        } else if (CurrencyConstant.THB.equals(ccy_no)) {
            params.put("mer_no", GlobalPayParamConstant.THB_MER_NO);
            secret = GlobalPayParamConstant.THB_SECRET;
        } else if (CurrencyConstant.INR.equals(ccy_no)) {
            params.put("mer_no", GlobalPayParamConstant.INR_MER_NO);
            secret = GlobalPayParamConstant.INR_SECRET;
        }
        params.put("mer_order_no", mer_order_no);
        params.put("acc_no", acc_no);
        params.put("acc_name", acc_name);
        params.put("ccy_no", ccy_no);
        params.put("order_amount", order_amount);
        params.put("bank_code", bank_code);
        params.put("mobile_no", mobile_no);
        params.put("province", province);
        params.put("notifyUrl", notifyUrl);
        params.put("summary", summary);
        String[] keys = params.keySet().toArray(new String[]{});
        StringBuilder stringBuilder = new StringBuilder();
        Arrays.sort(keys);
        for (String key : keys) {
            String val = String.valueOf(params.get(key) == null ? "" : params.get(key));
            if (Strings.isBlank(val)) {
                continue;
            }
            stringBuilder.append("&").append(key).append("=").append(val);
        }
        //排序后的参数
        String encodeParams = stringBuilder.deleteCharAt(0).toString();
        //拼接商户secret
        String strToHash = encodeParams + "&key=" + secret;
        //sign
        String hashResult = SecureUtil.md5(strToHash);
        params.put("sign", hashResult);
        return params;
    }


    /**
     * 校验提现回调
     *
     * @param globalPay
     * @param secret
     * @return
     */
    public static boolean verifyWithdrawNotify(GlobalPayWithdrawDTO globalPay, String secret) throws UnsupportedEncodingException {
        Map<String, String> params = Result.createMap(
                "err_code", globalPay.getErr_code(),
                "err_msg", globalPay.getErr_msg(),
                "mer_no", globalPay.getMer_no(),
                "mer_order_no", globalPay.getMer_order_no(),
                "order_amount", globalPay.getOrder_amount(),
                "ccy_no", globalPay.getCcy_no(),
                "order_no", globalPay.getOrder_no(),
                "create_time", globalPay.getCreate_time(),
                "pay_time", globalPay.getPay_time(),
                "status", globalPay.getStatus());
        String[] keys = params.keySet().toArray(new String[]{});
        Arrays.sort(keys);

        StringBuilder sb = new StringBuilder();
        Arrays.sort(keys);
        for (String key : keys) {
            String val = params.get(key);
            if (Strings.isBlank(val)) {
                continue;
            }
            sb.append("&").append(key).append("=").append(val);
        }
        //拼接商户secret
        String strToHash = sb.deleteCharAt(0).toString() + "&key=" + secret;
        //sign
        String hashResult = SecureUtil.md5(strToHash);
        return hashResult.equals(globalPay.getSign());
    }

    public static void main(String[] args) throws IOException {
//        GlobalPayUtil.testNotfiyVer();
//        GlobalPayUtil.testRecharge();
//        GlobalPayUtil.testW();
        testNotfiyPay();
    }

    public static void testWithdraw() throws IOException {
        UserWithdraw record = new UserWithdraw();
        record.setRealAmount(new BigDecimal("200"));
        record.setNo(Id.createOrderNo());
        Map<String, Object> withdrawParam = GlobalPayUtil.createWithdrawParam(
                record.getNo(),
                "8888888888123",
                "lisi",
                "IDR",
                "2000",
                "ACEH",
                "894974987498",
                "",
                "http://colorsos.ngrok.wendal.cn/open/globalpay/withdraw/notify",
                "sum"
        );
        System.err.println(withdrawParam);
        String respBody = GlobalPayUtil.send("http://wrysc.yudrsu.com/withdraw/singleOrder", withdrawParam);
        System.out.println(respBody);
//        JSONObject jsonObject = JSONUtil.parseToJSON(respBody);
        //验证状态
//        if (!jsonObject.getString("results").equals("success") || !jsonObject.getInteger("code").equals(0)) {
//            Result.breakWith(jsonObject.getString("results"));
//        }
    }

    public static void testRecharge() throws IOException {
        Map<String, Object> rechargeParam = GlobalPayUtil.createPayParam(
                "200",
                "http://colorsos.ngrok.wendal.cn/open/globalpay/recharge/notify/",
                Id.createOrderNo(),
                CurrencyConstant.INR,
                PayChannel.GLOBALPAY
        );
        System.out.println(rechargeParam);
        String respBody = GlobalPayUtil.send("http://zvfdh.yudrsu.com/ty/orderPay", rechargeParam);
        System.out.println(respBody);
        JSONObject jsonObject = JSONUtil.parseToJSON(respBody);
        System.out.println(jsonObject);
    }

    public static void testNotfiyWithdraw() throws UnsupportedEncodingException {
        //{"errCode":"!00000","errMsg":"!00000","merOrderNo":"202104121858180892","orderAmount":"20001.00","orderTime":"2021-04-12 17:58:24",
        // "payAmount":"20001.00","sign":"423454b10cc1552371254bb2b639313f","status":"SUCCESS"}
        GlobalPayWithdrawDTO dto = new GlobalPayWithdrawDTO();
        dto.setCcy_no("IDR");
        dto.setCreate_time("2021-04-12 20:01:12");
        dto.setErr_code("");
        dto.setErr_msg("");
        dto.setMer_no("gm761100000067975");
        dto.setMer_order_no("202104122101064562");
        dto.setOrder_amount("2000.00");
        dto.setOrder_no("202104120000002050238200112933");
        dto.setPay_time("");
        dto.setSign("da673c3759ace73b1b3dbf9bab7dc8d3");
        dto.setStatus("SUCCESS");

        System.out.println(GlobalPayUtil.verifyWithdrawNotify(dto, "0936D7E86164C2D53C8FF8AD06ED6D09"));

    }


    public static void testNotfiyPay() throws UnsupportedEncodingException {
        // {"busi_code":"100202","err_code":"!00000","err_msg":"!00000","mer_no":"gm761100000067975",
        // "mer_order_no":"202104181504520202","order_amount":"21504.00","order_no":"2104180000002379781140453110",
        // "order_time":"2021-04-18 14:04:53","pay_amount":"21504.00","pay_time":"2021-04-18 14:17:19",
        // "sign":"2750153f3787280b344b2879afb0e2d7","status":"SUCCESS"}
        GlobalPayRechargeDTO dto = new GlobalPayRechargeDTO();
        dto.setBusi_code("100202");
        dto.setErr_code("!00000");
        dto.setErr_msg("!00000");
        dto.setMer_no("gm761100000067975");
        dto.setMer_order_no("202104181504520202");
        dto.setOrder_amount("21504.00");
        dto.setOrder_no("2104180000002379781140453110");
        dto.setOrder_time("2021-04-18 14:04:53");
        dto.setPay_amount("21504.00");
        dto.setPay_time("2021-04-18 14:17:19");
        dto.setSign("2750153f3787280b344b2879afb0e2d7");
        dto.setStatus("SUCCESS");

        System.out.println(GlobalPayUtil.verifyRechargeNotify(dto, "0936D7E86164C2D53C8FF8AD06ED6D09"));

    }

}
